

#
# This file implements a rubics cube used for the RubicsLife Project
# Author: Alexander Esselink
# 
# Cube's layout:
# 
# up    :   grid[0] Yellow
# front :   grid[1] Orange
# right :   grid[2] Blue
# back  :   grid[3] Red
# left  :   grid[4] Green
# down  :   grid[5] White



import copy

class Cube:
    
    grid = {'up'    :   [['Y', 'Y', 'Y'],
                         ['Y', 'Y', 'Y'],
                         ['Y', 'Y', 'Y']],
            'front' :   [['O', 'O', 'O'],
                         ['O', 'O', 'O'],
                         ['O', 'O', 'O']],
            'right' :   [['B', 'B', 'B'],
                         ['B', 'B', 'B'],
                         ['B', 'B', 'B']],
            'back'  :   [['R', 'R', 'R'],
                         ['R', 'R', 'R'],
                         ['R', 'R', 'R']],
            'left'  :   [['G', 'G', 'G'],
                         ['G', 'G', 'G'],
                         ['G', 'G', 'G']],
            'down'  :   [['W', 'W', 'W'],
                         ['W', 'W', 'W'],
                         ['W', 'W', 'W']]}
             
    
    # up:  [2][0]  => right    [0][0]
    # up:  [2][1]  => right    [1][0]
    # up:  [2][2]  => right    [2][0]
            
    def operate(self, op):
        if op == 'u':
            self.rotUp('cw')
        elif op == 'f':
            self.rotFront('cw')
        elif op == 'r':
            self.rotRight('cw')
        elif op == 'b':
            self.rotBack('cw')
        elif op == 'l':
            self.rotLeft('cw')
        elif op == 'd':
            self.rotDown('cw')
        elif op == 'U':
            self.rotUp('ccw')
        elif op == 'F':
            self.rotFront('ccw')
        elif op == 'R':
            self.rotRight('ccw')
        elif op == 'B':
            self.rotBack('ccw')
        elif op == 'L':
            self.rotLeft('ccw')
        elif op == 'D':
            self.rotDown('ccw')

    
    
    def __init__(self):
        self.history = {'op':["start"],'cubes':[copy.deepcopy(self.grid)]}
        
        
    def save(self, op):
        self.history['cubes'].append(copy.deepcopy(self.grid))
        self.history['op'].append(op)
        
    def clrhis(self):
        self.history = {'op':[],'cubes':[]}
        
    def rotUp(self, direction):
    
        if direction == "cw":
            self.grid['up'] = [[self.grid['up'][2-x][y] for x in xrange(3)] for y in xrange(3)] # Rotate the up part of the cube
            sacrifice = self.grid['front'][0][::]
            self.grid['front'][0] = self.grid['right'][0][::]
            self.grid['right'][0] = self.grid['back'][0][::]  
            self.grid['back'][0] = self.grid['left'][0][::]
            self.grid['left'][0] = sacrifice[::]
        if direction == "ccw":
            self.grid['up'] = [[self.grid['up'][x][2-y] for x in xrange(3)] for y in xrange(3)] # Rotate the up part of the cube
            sacrifice = self.grid['front'][0][::]
            self.grid['front'][0] = self.grid['left'][0][::]
            self.grid['left'][0] = self.grid['back'][0][::]  
            self.grid['back'][0] = self.grid['right'][0][::]
            self.grid['right'][0] = sacrifice[::]
            
                        
        
    def rotFront(self, direction):
        if direction == "cw":
            self.grid['front'] = [[self.grid['front'][2-x][y] for x in xrange(3)] for y in xrange(3)] # Rotate the front part of the cube
            sacrifice = self.grid['up'][2][::]
            for i in xrange(3):
                self.grid['up'][2][2-i] = self.grid['left'][i][2]
                self.grid['left'][i][2] = self.grid['down'][0][i]
                self.grid['down'][0][i] = self.grid['right'][2-i][0]
                self.grid['right'][2-i][0] = sacrifice[2-i]
            
        if direction == "ccw":
            self.grid['front'] = [[self.grid['front'][x][2-y] for x in xrange(3)] for y in xrange(3)] # Rotate the front part of the cube
            sacrifice = self.grid['up'][2][::]
            for i in xrange(3):
                self.grid['up'][2][2-i] = self.grid['right'][2-i][0]
                self.grid['right'][2-i][0] = self.grid['down'][0][i]
                self.grid['down'][0][i] = self.grid['left'][i][2]
                self.grid['left'][i][2] = sacrifice[2-i]
                
            
    def rotRight(self, direction):
        if direction == "cw":
            self.grid['right'] = [[self.grid['right'][2-x][y] for x in xrange(3)] for y in xrange(3)] # Rotate the right part of the cube
            
            for i in xrange(3):
                tmp = self.grid['up'][i][2]
                self.grid['up'][i][2] = self.grid['front'][i][2]
                self.grid['front'][i][2] = self.grid['down'][i][2]
                self.grid['down'][i][2] = self.grid['back'][2-i][0]
                self.grid['back'][2-i][0] = tmp
            
        if direction == "ccw":
            self.grid['right'] = [[self.grid['right'][x][2-y] for x in xrange(3)] for y in xrange(3)] # Rotate the right part of the cube
            
            for i in xrange(3):
                tmp = self.grid['up'][i][2]
                self.grid['up'][i][2] = self.grid['back'][2-i][0]
                self.grid['back'][2-i][0] = self.grid['down'][i][2]
                self.grid['down'][i][2] = self.grid['front'][i][2]
                self.grid['front'][i][2] = tmp
        
    def rotBack(self, direction):
        
        if direction == "cw":
            self.grid['back'] = [[self.grid['back'][2-x][y] for x in xrange(3)] for y in xrange(3)] # Rotate the back part of the cube
            
            for i in xrange(3):
                tmp = self.grid['up'][0][2-i]
                self.grid['up'][0][2-i] = self.grid['right'][2-i][2]
                self.grid['right'][2-i][2] = self.grid['down'][2][i]
                self.grid['down'][2][i] = self.grid['left'][i][0]
                self.grid['left'][i][0] = tmp
            
        if direction == "ccw":
            self.grid['back'] = [[self.grid['back'][x][2-y] for x in xrange(3)] for y in xrange(3)] # Rotate the back part of the cube
            
            for i in xrange(3):
                tmp = self.grid['up'][0][2-i]
                self.grid['up'][0][2-i] = self.grid['left'][i][0]
                self.grid['left'][i][0] = self.grid['down'][2][i]
                self.grid['down'][2][i] = self.grid['right'][2-i][2]
                self.grid['right'][2-i][2] = tmp
            
    def rotLeft(self, direction):
        if direction == "cw":
            self.grid['left'] = [[self.grid['left'][2-x][y] for x in xrange(3)] for y in xrange(3)] # Rotate the left part of the cube
            
            for i in xrange(3):
                tmp = self.grid['up'][i][0]
                self.grid['up'][i][0] = self.grid['back'][2-i][2]
                self.grid['back'][2-i][2] = self.grid['down'][i][0]
                self.grid['down'][i][0] = self.grid['front'][i][0]
                self.grid['front'][i][0] = tmp
            
        if direction == "ccw":
            self.grid['left'] = [[self.grid['left'][x][2-y] for x in xrange(3)] for y in xrange(3)] # Rotate the left part of the cube
            
            for i in xrange(3):
                tmp = self.grid['up'][i][0]
                self.grid['up'][i][0] = self.grid['front'][i][0]
                self.grid['front'][i][0] = self.grid['down'][i][0]
                self.grid['down'][i][0] = self.grid['back'][2-i][2] 
                self.grid['back'][2-i][2] = tmp 
            
    def rotDown(self, direction):
        if direction == "cw":
            self.grid['down'] = [[self.grid['down'][2-x][y] for x in xrange(3)] for y in xrange(3)] # Rotate the down part of the cube
            
            for i in xrange(3):
                tmp = self.grid['front'][2][i]
                self.grid['front'][2][i] = self.grid['left'][2][i]
                self.grid['left'][2][i] = self.grid['back'][2][i]
                self.grid['back'][2][i] = self.grid['right'][2][i]
                self.grid['right'][2][i] = tmp
            
        if direction == "ccw":
            self.grid['down'] = [[self.grid['down'][x][2-y] for x in xrange(3)] for y in xrange(3)] # Rotate the down part of the cube
            
            for i in xrange(3):
                tmp = self.grid['front'][2][i]
                self.grid['front'][2][i] = self.grid['right'][2][i]
                self.grid['right'][2][i] = self.grid['back'][2][i]
                self.grid['back'][2][i] = self.grid['left'][2][i]
                self.grid['left'][2][i] = tmp
        
    def pprint(self):
        # print the history in a particular way
        print '\t'.join(['\t','up','front','right','back','left','down'])
        
        for n in range(len(self.history['cubes'])):
            print self.history['op'][n],
            cube = self.history['cubes'][n]
            for row in xrange(3):
                print '\t\t',
                for side in ['up','front','right','back','left','down']:
                    print ''.join(cube[side][row])+'\t',
                print ''
            print ''
            
        
